from libs.PipeLine import PipeLine, ScopedTiming
import os, sys, ujson, gc
import nncase_runtime as nn
import ulab.numpy as np
import image
import time
import ujson
from Face_recognition_model import FaceRecognition
from ai_inference import PersonKeyPointApp, init_ai_model, run_inference
from audio_player import AudioPlayer
import _thread
import machine
from face_registration import FaceRegistration
from face_registration import FaceRegistration
import usb
from warning_brief import Warning


class Config:
    def __init__(self):
        # 线程控制相关
        self.global_mutex = _thread.allocate_lock()
        self.stop_threads = False
        
        # 模式与状态控制
        self.current_mode = 0       # 0: 自动模式, 1: 签到模式, 2: 守护模式, 3: 注册模式
        self.current_model = 0      # 0: 人体关键点检测, 1: 人脸识别
        
        # 网络与通信相关
        # self.current_ip = None
        self.phone_number = ""
        # self.store_phone_number = ""
        self.ip_sign = False
        
        # 考勤管理相关
        self.face_library = {}                  # 人脸库，格式: {name: feature_array}
        
        # 时间同步相关
        self.local_time = None                  # 本地维护的时间
        self.last_sync_time = 0                 # 上次同步时间戳
        self.sync_interval = 30                 # 同步间隔(秒)
        self.time_synced = False                # 是否已同步过时间

        # 首次采用AT指令获取时间：

 
        # 模型实例
        self.fr = None

        # 用户数据
        # data = {"SMSC" : ["15139352096", 1],"class" : "6103","phone" : ["18203600458"],"century":20, "ip"= ""}
        self.user_path = "/sdcard/user/admin.json"

        self.data = self._give_necessary_data()
        self.century = self.data["century"]
        self.century_sign = False

        print(f"self.data = {self.data}")

    def _give_necessary_data(self):
        data = self.read_user(self.user_path)

        if data is None:
            print(f"警告：配置文件 {self.user_path} 不存在或格式错误")
            data = {}  # 设置为空字典，避免后续属性错误
        
        # print(f"data : {data}")

        
        return data
    
    def alter_necessary_data(self, user_path, data):
        self.write_user(user_path, data)
        return ;
    

    def read_user(self, file_path):
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = ujson.load(f)
            return content
        except FileNotFoundError:
            print(f"错误：文件 {file_path} 不存在")
            return None
        except ujson.JSONDecodeError:
            print(f"错误：文件 {file_path} 格式不正确（非 valid JSON）")
            return None
        except Exception as e:
            print(f"读取文件 {file_path} 失败：{str(e)}")
            return None

    def write_user(self, file_path, data):
        try:
            with open(file_path, 'w', encoding='utf-8') as f:
                ujson.dump(data, f)
            return True
        except TypeError as e:
            print(f"错误：数据无法序列化（可能包含不可 JSON 序列化的类型）：{str(e)}")
            return False
        except Exception as e:
            print(f"写入文件 {file_path} 失败：{str(e)}")
            return False

    def _upgrad_century(self):
        # 检查 local_time 格式是否符合预期
        if (self.local_time and self.local_time[0:10] == "0001010000"):
            # 安全地更新 century 值
            current_century = self.data.get("century", 0)  # 默认20世纪
            if current_century == 0:
                print(f"请检查admin.json文件,出现问题")
            self.data["century"] = current_century + 1
            self.century = current_century + 1
            
            # 保存更新
            self.alter_necessary_data(self.data)

class AlarmManager:
    def __init__(self, player):
        self.player = player
        self.active_alarms = {}  # 存储活跃警报及其触发时间
        self.priority_order = ["fall", "fight", "run", "crowd"]  # 优先级从高到低
        self.alarm_cooldown = {}  # 记录警报冷却时间
        self.time_window = 4.0  # 时间窗口为2秒
        
    def add_alarm(self, alarm_type):
        """添加警报，按优先级排序并控制重复发送"""
        current_time = time.time()
        
        # 检查是否为重复警报且在冷却时间内
        if alarm_type in self.alarm_cooldown:
            if current_time - self.alarm_cooldown[alarm_type] < self.time_window:
                print(f"[警报管理] 忽略重复警报: {alarm_type}")
                return
        self.alarm_cooldown[alarm_type] = current_time  # 更新冷却时间
        
        # 添加或更新警报时间
        self.active_alarms[alarm_type] = current_time
        
        # 清理过期警报（超过时间窗口的）
        self._cleanup_expired_alarms(current_time)
        
        # 按优先级排序并发送最高优先级警报
        self._send_highest_priority_alarm()
    
    def _cleanup_expired_alarms(self, current_time):
        """清理超过时间窗口的过期警报"""
        self.active_alarms = {
            alarm: timestamp for alarm, timestamp in self.active_alarms.items()
            if current_time - timestamp <= self.time_window
        }
    
    def _send_highest_priority_alarm(self):
        """按优先级排序并发送最高优先级的警报"""
        if not self.active_alarms:
            return
            
        # 按优先级顺序过滤出当前活跃的警报
        sorted_alarms = []
        for alarm in self.priority_order:
            if alarm in self.active_alarms:
                sorted_alarms.append(alarm)

        if not sorted_alarms:
            return
            
        highest_priority_alarm = sorted_alarms[0]
        print(f"[警报管理] 发送最高优先级警报: {highest_priority_alarm}")
        
        # 根据警报类型调用对应的player方法
        if highest_priority_alarm == "fall":
            self.player.play_fall_sound()
        elif highest_priority_alarm == "fight":
            self.player.play_fight_sound()
        elif highest_priority_alarm == "run":
            self.player.play_run_sound()
        elif highest_priority_alarm == "crowd":
            self.player.play_gather_sound()
    
    def clear_alarms(self):
        """清除所有活跃警报"""
        self.active_alarms = {}
        print("[警报管理] 清除所有警报")

class ES8266_message:
    def __init__(self, player, config, sms):
        self.player = player
        self.config = config
        self.sms = sms
        
        self.mode_names = ["自动模式", "签到模式", "守护模式", "注册模式"]
        self.attendance_start_time = 0          # 签到开始时间
        self.attendance_duration = 30           # 签到持续时间(秒)
        self.attendance_results = {"total": 0, "present": [], "absent": []}  # 考勤结果
        self.attendance_records = {}            # 记录每个人的签到时间
        self.last_attendance_check = 0          # 上次检查考勤的时间
        self.attendance_check_interval = 1      # 检查考勤的间隔(秒)
        self.attendance_display_time = 5        # 考勤结果显示时间(秒)
        self.attendance_display_start = 0       # 开始显示考勤结果的时间
        self.attendance_saved = False           # 是否已保存考勤结果
        self.index_f = 0                        # 可能的索引计数器,保证仅发一次
        self.store_phone_number = ""
        self.attendance_message_sent = False    #记录考勤结果是否已发送
        self.attendance_displayed = False       # 标记考勤结果是否已完成显示
        # 常用地址：
        self.database_dir="/sdcard/examples/utils/db/"
        self.save_dir = "/sdcard/attendance/"

        ## 实时课表
        self.class_time_slots = [
            (8*60+20, 8*60+30),   # 8:20-8:30
            (10*60+15, 10*60+25), # 10:15-10:25
            (13*60+50, 14*60+0),  # 13:50-14:00
            (15*60+45, 15*60+55),  # 15:45-15:55
            (18*60+20, 18*60+30)   # 18:20-15:30
        ]
    
    def check_reload_face_library(self):
        """定时重新加载人脸库"""
        if not hasattr(self, "last_reload_time"):
            self.last_reload_time = time.time()
        if time.time() - self.last_reload_time > 30:  # 每30秒检查一次
            self.config.face_library = self.load_face_library()
            self.last_reload_time = time.time()
    
    
    def parse_received_data(self):

        self.config.face_library = self.load_face_library()

        while not self.config.stop_threads:

            
            data = player.read()
            print(data)
            if not data:
                time.sleep(0.1)
                continue
            
            # 查找有效数据起始位置（假设以\xfa开头）
            start_idx = data.find(b'\xfa')
            if start_idx != -1:
                data = data[start_idx:]  # 从\xfa开始截取
                print(f"裁剪后数据: {data}")

            try:
                data_str = data.decode('utf-8').strip()
            except UnicodeError:
                try:
                    data_str = data.decode('gbk').strip()
                except UnicodeError as e:
                    print(f"解码失败，原始数据: {data}，错误: {e}")
                    continue  
            parts = data_str.split(',')
            print(f"parts == {parts}")
        
            for part in parts:
                # 解析IP地址
                if part.startswith('IP:'):
                    ip = part[3:]
                    if len(ip.split('.')) == 4 and all(c.isdigit() or c == '.' for c in ip):
                        with self.config.global_mutex:
                            # self.config.current_ip = ip
                            print(f"ip == {ip}\n 类型 = {type(ip)}")
                            if self.config.data["ip"] != ip:
                                self.config.data["ip"] = ip
                                self._upgrade_ip()
                            if not self.config.ip_sign:
                               self.sms.send_ip_message(self.config.data["ip"])
                               self.config.ip_sign = True
                            
                            
                        print(f"✅ IP更新: {self.config.data["ip"]}")
                    
                # 解析模式命令
                elif part == 'conmod0':
                    with self.config.global_mutex:
                        self.config.current_mode = 0
                    print("✅ 切换到自动模式")
                
                elif part == 'conmod1':
                    with self.config.global_mutex:
                        self.config.current_mode = 1
                        self.attendance_start_time = time.time()
                        self.attendance_saved = False
                        self.reset_attendance()  # 重置考勤记录
                        self.index_f=1
                    print("✅ 切换到签到模式")
                
                elif part == 'conmod2':
                    with self.config.global_mutex:
                        self.config.current_mode = 2
                    print("✅ 切换到守护模式")
                
                elif part == 'conmod3':
                    with self.config.global_mutex:
                        self.config.current_mode = 3
                    print("✅ 切换到注册模式")
    
                # 解析人脸解析命令（触发人脸注册）
                elif part == 'faceres':
                    print("✅ 人脸解析命令")
                    self.register_faces()

                # 解析手机号
                elif part.startswith('ph0:'):
                    phone = part[4:]
                    print(f"未进入前, {phone}, 类型：{type(phone)}")
                    # if(len(phone) != 11):
                    #     print(f"phone的长度:{len(phone)}")
                    # if not phone.isdigit():
                    #     print(f"什么不是数字？")
                    if len(phone) == 11 and phone.isdigit():
                        self.store_phone_number = phone
                        # print(f"phone = {phone}")
                        self.config.data["phone"].append(self.store_phone_number)
                        self.config.alter_necessary_data(self.config.user_path, self.config.data)
                        # print(f"self.config.data[phone] = {self.config.data["phone"]}")
                        print(f"✅ 手机号已存储: {self.store_phone_number}")
                
                elif part.startswith('ph1:'):
                    phone = part[4:]
                    if len(phone) == 11 and phone.isdigit():
                        self.config.phone_number = phone
                        print(f"✅ 手机号更新: {self.config.phone_number}")
                    
                # 解析时间信息 (格式: YYMMDDHHMMSS)
                elif len(part) == 12 and part.isdigit():
                    with self.config.global_mutex:
                        # 更新本地时间
                        self.config.local_time = part
                        self.config._upgrad_century()
                        # self.sms.update_time()
                        self.config.last_sync_time = time.time()
                        self.config.time_synced = True
                    print(f"✅ 时间同步: {self.config.local_time}")
    
    def _upgrade_ip(self):
        print(f"更新ip地址了\n data = {self.config.data}")   
        # 保存更新
        self.config.alter_necessary_data(self.config.user_path, self.config.data) 

    def register_faces(self):
        """执行人脸注册流程"""
        face_det_kmodel_path="/sdcard/examples/kmodel/face_detection_320.kmodel" 
        # 人脸注册模型路径 
        face_reg_kmodel_path="/sdcard/examples/kmodel/face_recognition.kmodel" 
        # 其它参数 
        anchors_path="/sdcard/examples/utils/prior_data_320.bin" 
        database_dir="/sdcard/examples/utils/db/" 
        database_img_dir="/sdcard/examples/utils/db_img/" 
        face_det_input_size=[320,320] 
        face_reg_input_size=[112,112] 
        confidence_threshold=0.5 
        nms_threshold=0.2 
        anchor_len=4200 
        det_dim=4 
        anchors = np.fromfile(anchors_path, dtype=np.float) 
        anchors = anchors.reshape((anchor_len,det_dim)) 
        max_register_face = 100 #数据库最多人脸个数 
        feature_num = 128 #人脸识别特征维度 
  
        fr=FaceRegistration(face_det_kmodel_path,face_reg_kmodel_path,det_input_size=face_det_input_size,reg_input_size=face_reg_input_size,database_dir=database_dir,anchors=anchors,confidence_threshold=confidence_threshold,nms_threshold=nms_threshold) 
        try: 
            # 获取图像列表 
            img_list = os.listdir(database_img_dir) 
            for img_file in img_list: 
                #本地读取一张图像 
                full_img_file = database_img_dir + img_file 
                print(full_img_file) 
                img = image.Image(full_img_file) 
                img.compress_for_ide() 
                # 转rgb888的chw格式 
                rgb888p_img_ndarry = fr.image2rgb888array(img) 
                # 人脸注册 
                fr.run(rgb888p_img_ndarry,img_file) 
                gc.collect() 
        except Exception as e: 
            sys.print_exception(e) 
        finally: 
            fr.face_det.deinit() 
            fr.face_reg.deinit() 
    
    def load_face_library(self):
        """加载人脸特征库"""

        try:
            # 检查目录是否存在
            try:
                os.stat(self.database_dir)
            except OSError:
                print(f"人脸库目录 {self.database_dir} 不存在")
                return self.config.face_library
            
            # 获取目录中的所有文件
            try:
                files = os.listdir(self.database_dir)
            except OSError as e:
                print(f"无法列出目录 {self.database_dir} 的内容: {e}")
                return self.config.face_library
            
            bin_files = [f for f in files if f.endswith('.bin')]
            if not bin_files:
                print(f"警告: 人脸库目录 {self.database_dir} 中没有找到.bin文件")
                return self.config.face_library
            
            for file in bin_files:
                name = file.split('.')[0]       
                file_path = self.database_dir + '/' + file
                try:
                    with open(file_path, "rb") as f:
                        data = f.read()
                        feature = np.frombuffer(data, dtype=np.float)
                    
                        # 验证特征向量长度
                        if len(feature) == 128:
                            self.config.face_library[name] = feature
                        elif len(feature) == 512:
                            print(f"警告: 文件 {file} 包含512维特征向量，截取前128维使用")
                            self.config.face_library[name] = feature[:128]  # 截取前128维
                        else:
                            print(f"警告: 文件 {file} 中的特征向量长度不正确: {len(feature)}")
                except Exception as e:
                    print(f"无法加载人脸特征 {file}: {e}")
            
            print(f"成功加载 {len(self.config.face_library)} 个人脸特征")
            if not self.config.face_library:
                print("警告: 加载的人脸库为空")
        except Exception as e:
            print(f"加载人脸库错误: {e}")
    
        # 打印加载的特征信息，用于调试
        for name, feature in self.config.face_library.items():
            print(f"已加载特征: {name}, 维度: {len(feature)}")
        
        return self.config.face_library
    
    def reset_attendance(self):
        """重置考勤记录"""
        self.attendance_results = {"total": len(self.config.face_library), "present": [], "absent": list(self.config.face_library.keys())}
        self.attendance_records = {}
        self.attendance_message_sent = False  # 重置时也重置消息发送状态
        self.attendance_display_start = 0  # 重置显示开始时间
        self.attendance_displayed = False  # 重置显示标志
        print(f"考勤已重置: 应到{self.attendance_results['total']}人")
    
    def is_in_class_time(self, hour, minute):
        """判断当前时间是否在上课时间段内"""
        current_minute = hour * 60 + minute
        for start, end in self.class_time_slots:
            if start <= current_minute <= end:
                return True
        return False
    
    def draw_terminal_info(self, pl):
        """在界面上绘制终端信息"""
        # 获取当前模式和模型（线程安全）
        with self.config.global_mutex:
            current_mode_display = self.config.current_mode
            current_model = self.config.current_model  # 0:人体关键点，1:人脸识别
        
        # 模式显示
        mode_text = f"当前模式: {self.mode_names[current_mode_display] if current_mode_display < len(self.mode_names) else '未知模式'}"
        pl.osd_img.draw_string_advanced(320, 50, 30, mode_text, color=(255, 255, 0), align=1)
        
        # 时间显示
        time_display = "未同步时间"
        with self.config.global_mutex:
            if self.config.local_time:
                time_display = f"{self.config.century}{self.config.local_time[0:2]}-{self.config.local_time[2:4]}-{self.config.local_time[4:6]} {self.config.local_time[6:8]}:{self.config.local_time[8:10]}:{self.config.local_time[10:12]}"
                sync_status = "已同步" if self.config.time_synced else "未同步"
                sync_indicator = "●" if (time.time() % 2 < 1) else "○"
                time_display += f" ({sync_status} {sync_indicator})"
                hour = int(self.config.local_time[6:8])
                minute = int(self.config.local_time[8:10])
                if self.is_in_class_time(hour, minute):
                    time_display += " [上课前]"
        pl.osd_img.draw_string_advanced(320, 110, 30, f"时间: {time_display}", color=(255, 192, 203), align=1)
        
        # 显示同步倒计时
        if self.config.time_synced:
            remaining = self.config.sync_interval - (time.time() - self.config.last_sync_time)
            countdown = max(0, int(remaining))
            pl.osd_img.draw_string_advanced(320, 140, 20, f"下次同步: {countdown}秒", color=(128, 128, 255), align=1)
        
        # 【关键修改】仅当运行人脸识别模型（current_model == 1）时，显示签到相关信息
        if current_model == 1:
            elapsed = time.time() - self.attendance_start_time
            remaining = max(0, self.attendance_duration - elapsed)
            
            # 显示考勤倒计时
            pl.osd_img.draw_string_advanced(320, 170, 20, 
                f"签到剩余: {int(remaining)}秒", color=(255, 165, 0), align=1)
            
            # 显示实时考勤结果
            present_count = len(self.attendance_results["present"])
            total_count = self.attendance_results["total"]
            pl.osd_img.draw_string_advanced(320, 200, 20, 
                f"实时考勤: {present_count}/{total_count}人已签到", color=(0, 255, 0), align=1)
            
            # 考勤结束后显示完整结果
            if elapsed >= self.attendance_duration:
                if not self.attendance_displayed and self.attendance_display_start == 0:
                    self.attendance_display_start = time.time()
                    self.attendance_displayed = True
                if self.attendance_display_start != 0:
                    self.display_attendance_results(pl)
                    if time.time() - self.attendance_display_start > self.attendance_display_time:
                        self.attendance_display_start = 0
        
    def update_local_time(self):
        """更新本地时间，每秒钟递增一次"""
        
        if not self.config.local_time:
            return  # 还没有同步过时间，不更新
            
        # 解析当前时间
        year = int(self.config.local_time[0:2])
        month = int(self.config.local_time[2:4])
        day = int(self.config.local_time[4:6])
        hour = int(self.config.local_time[6:8])
        minute = int(self.config.local_time[8:10])
        second = int(self.config.local_time[10:12])
        
        # 增加1秒
        second += 1
        if second >= 60:
            second = 0
            minute += 1
            if minute >= 60:
                minute = 0
                hour += 1
                if hour >= 24:
                    hour = 0
                    day += 1
                    # 简单的月份天数计算（不考虑闰年）
                    days_in_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
                    if day > days_in_month[month-1]:
                        day = 1
                        month += 1
                        if month > 12:
                            month = 1
                            year += 1
        
        # 格式化为字符串
        with self.config.global_mutex:
            self.config.local_time = f"{year:02d}{month:02d}{day:02d}{hour:02d}{minute:02d}{second:02d}"


    def process_attendance(self, recg_results):

        current_time = time.time()
        
        # 1. 提取当前帧识别到的人脸，更新历史签到记录
        for result in recg_results:
            if isinstance(result, str) and "name:" in result and "unknown" not in result:
                # 提取名字（与原逻辑一致）
                name_start = result.find("name: ") + 6
                name_end = result.find(",", name_start)
                if name_end == -1:
                    name_end = len(result)
                name = result[name_start:name_end].strip()
                
                # 记录首次签到时间（核心：只记录第一次出现）
                if name in self.config.face_library and name not in self.attendance_records:
                    self.attendance_records[name] = current_time  # 历史记录累加
                    print(f"考勤记录: {name} 已签到")
        
        # 2. 基于历史所有签到记录统计结果（核心修复）
        all_present = set(self.attendance_records.keys())  # 所有曾经签到的人
        self.attendance_results["present"] = list(all_present)
        self.attendance_results["absent"] = [name for name in self.config.face_library.keys() if name not in all_present]
        print(f"当前考勤状态: 实到{len(self.attendance_results['present'])}人，未到{len(self.attendance_results['absent'])}人")
        # 3. 考勤结束后保存结果（不变）
        if current_time - self.attendance_start_time >= self.attendance_duration and not self.attendance_saved:
            self.attendance_saved = True
        

    def display_attendance_results(self, pl):
        """显示考勤结果"""
        result_text = "考勤结束 - 结果:\r\n"
        result_text += f"应到: {self.attendance_results['total']}人\r\n"
        result_text += f"实到: {len(self.attendance_results['present'])}人\r\n"
        result_text += f"未到: {len(self.attendance_results['absent'])}人\r\n\r\n"

        
        # 显示实到人员
        result_text += "实到名单:\r\n"
        present_names = ", ".join(self.attendance_results["present"])
        if present_names:
            result_text += present_names
        else:
            result_text += "无"
        
        # 显示未到人员
        result_text += "\r\n\r\n未到名单:\r\n"
        absent_names = ", ".join(self.attendance_results["absent"])
        if absent_names:
            result_text += absent_names
            result_text += "\r\n"
            print(f"{result_text}")
            current_time = time.time()
            if (self.config.current_mode in (0, 1)  # 自动模式或签到模式
                and current_time - self.attendance_start_time >= self.attendance_duration  # 考勤已结束
                and not self.attendance_message_sent):  # 尚未发送过消息
                
                self.attendance_message_sent = True  # 标记为已发送
                self.player.send(result_text)
                self.sms.send_attendance_message(self.attendance_results)
                self.config.current_mode = 0

        else:
            result_text += "无"
        
        pl.osd_img.draw_string_advanced(320, 230, 20, result_text, color=(0, 0, 255), align=1)

    def recognize_face(self, img):
        """人脸识别并与库中特征对比"""

        # print(f"人脸识别模型初始化:{self.config.fr}")

        if not self.config.fr or not self.config.fr:
            print("人脸识别模型未初始化或未就绪")
            return [], []
            
        # 使用FaceRecognition类的run方法进行识别
        det_boxes, recg_res = self.config.fr.run(img)

        print(f"recg_res: {recg_res}\n 类别:{type(recg_res)}")
        
        # 打印调试信息
        print(f"识别结果数量: {len(recg_res)}")
        for i, res in enumerate(recg_res):
            print(f"结果 {i}: {res}")
        
        # 处理识别结果
        for i, res in enumerate(recg_res):
            if isinstance(res, str) and "name:" in res:
                # 提取名字
                name_start = res.find("name: ") + 6
                name_end = res.find(",", name_start)
                if name_end == -1:
                    name_end = len(res)
                name_str = res[name_start:name_end].strip()
                print(f"识别到的名字: {name_str}(是否在人脸库中: {name_str in self.config.face_library})")
            
                # print(f"recognize_face:{recognize_face}")
                
                # 更新识别结果
                if name_str != 'unknown':
                    # 修改绘制结果，确保显示正确
                    if det_boxes and i < len(det_boxes):
                        x1, y1, w, h = map(lambda x: int(round(x, 0)), det_boxes[i][:4])
                        x1 = x1 * self.config.fr.display_size[0]//self.config.fr.rgb888p_size[0]
                        y1 = y1 * self.config.fr.display_size[1]//self.config.fr.rgb888p_size[1]
                        self.config.fr.pl.osd_img.draw_rectangle(x1, y1, w, h, color=(255, 0, 0, 255), thickness=4)
                        self.config.fr.pl.osd_img.draw_string_advanced(x1, y1, 32, f"识别: {name_str}", color=(255, 255, 0, 0))
        # 仅在签到模式下处理考勤
        current_time = time.time()
        if (self.config.current_mode == 0 or self.config.current_mode == 1) and current_time - self.attendance_start_time < self.attendance_duration:
            # 定期处理考勤结果，避免每次循环都处理
            if current_time - self.last_attendance_check > self.attendance_check_interval:
                self.process_attendance(recg_res)
                self.last_attendance_check = current_time
        
        return det_boxes, recg_res
        
    
class Model:
    def __init__(self, config):
        self.config = config
        self.person_kp = None
        self.detector = None
        self.person_kmodel_path = "/sdcard/examples/kmodel/yolov8n-pose.kmodel"
        
    def init_person_model(self, rgb888p_size, display_size):
        """初始化人体关键点模型"""
        self.person_kp, self.detector = init_ai_model(self.person_kmodel_path, rgb888p_size=rgb888p_size, display_size=display_size)
        print("✅ 人体关键点模型初始化完成")

    def init_face_model(self, pl):
        """初始化人脸识别模型"""
        
        # 初始化人脸识别模型
        self.config.fr = FaceRecognition(pl=pl, debug_mode=0)

        print(f"init_face_model: {self.config.fr}")

        if not self.config.fr:
            print("错误: 人脸识别模型未初始化")
            return [], []

        
        # 将全局人脸库同步到FaceRecognition实例
        if self.config.face_library:
            self.config.fr.db_name = list(self.config.face_library.keys())
            self.config.fr.db_data = list(self.config.face_library.values())
            self.config.fr.valid_register_face = len(self.config.face_library)
            print(f"已将{len(self.config.face_library)}个全局人脸特征同步到FaceRecognition实例")
        
        print("✅ 人脸识别模型初始化完成")

    def switch_to_person_model(self, rgb888p_size, display_size, pl):
        """切换到人体关键点模型"""
        
        # 释放人脸识别模型
        if self.config.fr:
            try:
                self.config.fr.face_det.deinit()
                self.config.fr.face_reg.deinit()
                self.config.fr = None
                print("✅ 人脸识别模型已释放")
            except Exception as e:
                print(f"释放人脸识别模型时出错: {e}")
        
        # 初始化人体关键点模型
        if not self.person_kp or not self.detector:
            self.init_person_model(rgb888p_size, display_size)
        
        time.sleep(1)  # 等待模型初始化完成

    def switch_to_face_model(self, pl):
        """切换到人脸识别模型""" 
        # 释放人体关键点模型
        if self.person_kp:
            try:
                self.person_kp.deinit()
                self.person_kp = None
                self.detector = None
                print("✅ 人体关键点模型已释放")
            except Exception as e:
                print(f"释放人体关键点模型时出错: {e}")
        
        # 初始化人脸识别模型
        if not self.config.fr:
            self.init_face_model(pl)
        
        time.sleep(1)  # 等待模型初始化完成


class phone_message:
    def __init__(self, config,serial):
        self.config = config
        # 用户配置路径
        # self.user_path = user_path

        # data = {"SMSC" : ["15139352096", 1],"class" : "6103","phone" : ["18203600458"],"century":20, "ip"= ""}
        # self.data = self._give_necessary_data()

        # print(f"self.data['SMSC'][0] = {self.data["SMSC"][0]} {type(self.data["SMSC"][0])}")
        # print(f"self.data['SMSC'][1] = {self.data["SMSC"][1]} {type(self.data["SMSC"][1])}")

        # self.ip = self.config.data["ip"] 
        self.warning = Warning(serial, self.config.data["SMSC"][0], self.config.data["SMSC"][1])
      
    def update_time(self):  
        if self.config.local_time is None:
            print(f"config.local_time竟然是空的")
            return False

        self.year = f"{str(self.config.data["century"])}{self.config.local_time[0:2]}"
        self.month = f"{self.config.local_time[2:4]}"
        self.day = f"{self.config.local_time[4:6]}"
        self.hour = f"{self.config.local_time[6:8]}"
        self.minute = f"{self.config.local_time[8:10]}"
        self.sec = f"{self.config.local_time[10:12]}"

        return True
    
    def _init_SMSC(self):
        if self.config.data["SMSC"][1] == 0:
            self.warning.DistributionNetwork()
            self.config.data["SMSC"][1] = 1
            self.config.alter_necessary_data(self.config.user_path, self.config.data)


    def assemble_warn_message(self, warning):
        """
        构建的warn_str
        > ({班级},{警告},{年},{月},{日},{时},{分},{秒})
        """
        warn_str = []
        warn_str.append(self.config.data["class"])
        warn_str.append(warning)
        warn_str.append(self.year)
        warn_str.append(self.month)
        warn_str.append(self.day)
        warn_str.append(self.hour)
        warn_str.append(self.minute)
        warn_str.append(self.sec)

        return tuple(warn_str)
    
    def send_warn_message(self, warning):

        self._init_SMSC()
        if self.update_time():
            message = self.assemble_warn_message(warning)
            for phone_number in self.config.data["phone"]:
                # print(f"看电话来了: {phone_number}\n {type(phone_number)}")
                self.warning.Send_Message(message, phone_number)
            if self.config.phone_number not in self.config.data["phone"]:
                self.warning.Send_Message(message, self.config.phone_number)

    
    def assemble_attendance_message(self, attendance_results):
        """
        > ({班级},{未到},{总人数},{年},{月},{日},{时},{分},{秒})
        """
        attendance_str = []
        attendance_str.append(self.config.data["class"])
        attendance_str.append(str(len(attendance_results['absent'])))
        attendance_str.append(str(attendance_results['total']))
        attendance_str.append(self.year)
        attendance_str.append(self.month)
        attendance_str.append(self.day)
        attendance_str.append(self.hour)
        attendance_str.append(self.minute)
        attendance_str.append(self.sec)

        return tuple(attendance_str)
    
    def send_attendance_message(self, attendance_results):

        self._init_SMSC()
        if self.update_time():

            message = self.assemble_attendance_message(attendance_results)
            print(f" self.config.data[phone] = {self.config.data["phone"]}")
            for phone_number in self.config.data["phone"]:
                print(f"看电话来了: {phone_number}\n {type(phone_number)}")
                self.warning.Send_Message(message, phone_number)
            if self.config.phone_number not in self.config.data["phone"]:
                self.warning.Send_Message(message, self.config.phone_number)

    def assemble_ip_message(self, ip):
        """
        构建的warn_str
        > ({班级},{IP})
        """
        ip_str = []
        ip_str.append(self.config.data["class"])
        ip_str.append(ip)

        return tuple(ip_str)
    
    def send_ip_message(self,ip):

        self._init_SMSC()
        message = self.assemble_ip_message(ip)
        for phone_number in self.config.data["phone"]:
            # print(f"看电话来了: {phone_number}\n {type(phone_number)}")
            self.warning.Send_Message(message, phone_number)
        if self.config.phone_number not in self.config.data["phone"]:
            self.warning.Send_Message(message, self.config.phone_number)

    def get_real_time(self):
        local_time, century = self.warning.get_RealTime()
        return local_time, century
       



if __name__ == "__main__":

    # 模型配置
    rgb888p_size = [1280, 720]
    display_size = [960, 540]

    serial = usb.Serial("/dev/ttyUSB1", 500)

    config = Config()
    config.ip_sign = False
    player = AudioPlayer()

    sms = phone_message(config, serial)

    es8266 = ES8266_message(player, config, sms)
    
    model = Model(config)

    # 首次初始化时间：
    # config.init_local_time(sms.get_real_time)
    

    # 创建共享的PipeLine实例
    pl = PipeLine(rgb888p_size=rgb888p_size, display_mode="lcd")
    pl.create(vflip=True)


    # 加载人脸库
    config.face_library = es8266.load_face_library()

    # print(f"config.face_library: {config.face_library}")
    
    # 初始化考勤结果
    print(f"es8266.config.face_library: {es8266.config.face_library}")
    es8266.reset_attendance()
    
    alarm_manager = AlarmManager(player)
    
    # 初始化默认模型（人体关键点检测）
    model.init_person_model(rgb888p_size, display_size)
    
    # 启动数据解析线程
    data_thread = _thread.start_new_thread(es8266.parse_received_data, ())

    last_second = 0

    last_mode = config.current_mode
    last_model = config.current_model

    player.send("restart")
    last_in_class = False
    try:
        while True:
            current_timestamp = time.time()
            
            # 每秒更新一次本地时间
            current_second = int(current_timestamp)
            if current_second != last_second:
                last_second = current_second
                es8266.update_local_time()

            # 根据模式切换模型
            with config.global_mutex:
                if config.current_mode == 3:
                    target_model = 3  # 注册模式，不运行任何检测
                elif config.current_mode == 1:
                    target_model = 1  # 签到模式，运行人脸识别
                elif config.current_mode == 2:
                    target_model = 0  # 守护模式，运行人体关键点检测
                else:  # 自动模式
                    if config.local_time:
                        hour = int(config.local_time[6:8])
                        minute = int(config.local_time[8:10])
                        if es8266.is_in_class_time(hour, minute):
                            target_model = 1  # 上课时间运行人脸识别
                        else:
                            target_model = 0  # 其他时间运行人体关键点检测
                    else:
                        target_model = 0  # 时间未同步，默认运行人体关键点检测
            
            # 执行模型切换（如果需要）
            if target_model != config.current_model:
                print(f"切换模型: {config.current_model} -> {target_model}")
                if target_model == 0:  # 切换到人体关键点检测
                    model.switch_to_person_model(rgb888p_size, display_size, pl)
                elif target_model == 1:  # 切换到人脸识别
                    model.switch_to_face_model(pl)
                config.current_model = target_model
                
                with config.global_mutex:
                    current_mode = config.current_mode
                
                if config.local_time:
                    hour = int(config.local_time[6:8])
                    minute = int(config.local_time[8:10])
                    current_in_class = es8266.is_in_class_time(hour, minute)
                    
                    # 当自动模式下刚进入上课时间（8:20），重置考勤
                    if current_mode == 0 and current_in_class and not last_in_class:
                        es8266.attendance_start_time = current_timestamp
                        es8266.attendance_saved = False
                        es8266.reset_attendance()  # 调用reset_attendance，会重置attendance_message_sent
                        print(f"自动模式：进入上课时间，开始考勤（8:20-8:30）")
                    
                    # 当自动模式下离开上课时间（8:30），强制结束考勤
                    if current_mode == 0 and not current_in_class and last_in_class:
                        if not es8266.attendance_saved:                          
                            es8266.attendance_saved = True
                            # 确保离开上课时间时发送一次消息（如果之前没发过）
                            # if not es8266.attendance_message_sent:
                            #     es8266.attendance_message_sent = True
                            #     # es8266.player.send(result_text)  # 此处需要获取result_text，可能需要重构代码
                            #     sms.send_attendance_message(es8266.attendance_results)
                        print(f"自动模式：离开时间，考勤结束（8:30后）")
                    
                    last_in_class = current_in_class
            # 运行相应模型
            if config.current_model == 0:  # 人体关键点检测
                # 执行AI推理
                results = run_inference(model.person_kp, model.detector, pl, current_timestamp)
                
                # 处理检测结果 - 使用报警管理器
                if results["fall"]:
                    alarm_manager.add_alarm("fall")
                    sms.send_warn_message("注意，有人跌倒")
                # elif results["fight"]:
                #     alarm_manager.add_alarm("fight")
                # elif results["run"]:
                #     alarm_manager.add_alarm("run")
                elif results["crowd"]:
                    alarm_manager.add_alarm("crowd")
                    sms.send_warn_message("注意，异常聚集")
                else:
                    pass
            
            elif config.current_model == 1:  # 人脸识别
                img = pl.get_frame()
                det_boxes, recg_res = es8266.recognize_face(img)
                config.fr.draw_result(det_boxes, recg_res)
            
            else:  # 不运行任何检测

                time.sleep(0.1)
            # 获取温度
            temp = machine.temperature()
            # 温度显示（左上角）
            temp_text = f"温度: {temp:.1f}摄氏度"
            pl.osd_img.draw_string_advanced(20, 30, 30, temp_text, color=(30, 144, 255))
            # 绘制终端信息
            es8266.draw_terminal_info(pl)
            es8266.check_reload_face_library()
        
            pl.show_image()
            gc.collect()

    except KeyboardInterrupt:
        print("\nKeyboardInterrupt导致程序已停止")
    finally:
        print("\n程序已停止")
        # 停止数据解析线程
        stop_threads = True
        time.sleep(0.5)  # 给线程时间退出
        
        # 释放所有模型资源
        if model.person_kp:
            model.person_kp.deinit()
        if config.fr:
            config.fr.face_det.deinit()
            config.fr.face_reg.deinit()
        pl.destroy()